///////////////////////////////////////////////////////////////////////////////
//
//  Copyright (C) 2007-2009 ILOG, S.A.
//  All Rights Reserved.
//  The following is ILOG Source Code.  No modifications may be made to the  
//  ILOG Source Code.  Any usage of the ILOG Source Code is subject to 
//  the terms and conditions of the ILOG End User License Agreement   
//  applicable to this ILOG software product.
//
///////////////////////////////////////////////////////////////////////////////

package ilog.gauges.circular.renderers
{
  import flash.display.DisplayObject;
  import flash.geom.Point;
  import flash.text.TextFormat;
  
  import ilog.gauges.gaugesClasses.circular.CircularGaugeElement;
  import ilog.utils.CSSUtil;
  
  import mx.core.IDataRenderer;
  import mx.core.IFlexDisplayObject;
  import mx.core.UITextField;
  import mx.styles.CSSStyleDeclaration;

  /**
   * Horizontal alignment of the label relative to the origin point.
   * Possible values are: <code>"left"</code>, <code>"center"</code>,
   * and <code>"right"</code>.
   *
   * @default "center"
   */ 
  [Style(name="horizontalAlign", type="String", enumeration="left,center,right", inherit="no")]

  /**
   * Vertical alignment of the label relative to the origin point.
   * Possible values are: <code>"top"</code>, <code>"middle"</code>,
   * and <code>"bottom"</code>.
   *
   * @default "middle"
   */      
  [Style(name="verticalAlign", type="String", enumeration="top,middle,bottom", inherit="no")]
  
  [DefaultProperty("text")]  

  /**
   * This class allows you to add a label to a circular gauge.
   * The position of the label is controlled by <code>horizontalAlign</code>,
   * <code>verticalAlign</code>, and the origin point.
   * The font size of the label can be expressed as a percentage to construct 
   * fully-scalable gauges.
   *  
   * @mxml
   *  
   * <p>The <code>&lt;ilog:CircularLabelRenderer&gt;</code> tag inherits all the properties
   * of its parent classes and adds the following properties:</p>
   *  
   * <pre>
   * &lt;ilog:CircularLabelRenderer
   *   <strong>Properties</strong>
   *   text=""
   *   labelRenderer="<i>UITextField</i>"
   *   labelFontSize="10%"
   * 
   *   <strong>Styles</strong>
   *   horizontalAlign="center|left|right"
   *   verticalAlign="middle|top|bottom"
   * /&gt;
   * </pre>
   *  
   * @see ilog.gauges.gaugesClasses.circular.CircularGaugeElement
   * @includeExample examples/CircularLabelRendererExample.mxml -noswf
   */  
  public class CircularLabelRenderer extends CircularGaugeElement
  {

    /**
     *  @private 
     */    
    private var _label:UITextField;

    /**
     *  @private 
     */
    private var _text:String;

    /**
     *  @private
     */
    private static var stylesInited:Boolean = initStyles(); 

    /**
     *  @private
     */
    private static function initStyles():Boolean
    {
      var nStyle:CSSStyleDeclaration =
        CSSUtil.createSelector("CircularLabelRenderer");   
            
      nStyle.defaultFactory = function():void  {
        this.horizontalAlign="center";
        this.verticalAlign="middle";
      }

      return true;
    }
    
    /**
     * Constructor 
     */    
    public function CircularLabelRenderer()
    {
      super();
      _label = new UITextField();
      labelRenderer = _label;
    }

    private var _labelRenderer:DisplayObject = null;
    
    [Inspectable(category="General")]
    
    /** 
     *  A reference to the display object used to render the label. 
     *  This property must implement the <code>IDataRenderer</code>
     *  and <code>IFlexDisplayObject</code> interfaces.
     *  If this property is <code>null</code>, a <code>UITextField</code> is used internally.
     *  The <code>data</code> property of the labelRenderer is assigned a String 
     *  object containing the text to be rendered.
     *
     *  @default null
     *  @since ILOG Elixir 2.0
     *  @ilog.reviewed SH 27 July 08
     */
    public function get labelRenderer():DisplayObject
    {
      if (_labelRenderer == _label)
        return null;
      else 
        return _labelRenderer;
    }

    /**
     *  @private
     */ 
    public function set labelRenderer(value:DisplayObject):void
    {
      if (_labelRenderer == value)
          return;

      if (_labelRenderer != null && contains(_labelRenderer))
        removeChild(_labelRenderer);
      
      
      if (value == null)
        _labelRenderer = _label;
      else
        _labelRenderer = value;
          
      addChild(_labelRenderer);
      invalidateProperties();
    }
    
    /**
     *  @private 
     */
    private var _percentLabelFontSize:Number = 10;

    [Inspectable(environment="none")]

    /**
     *  Number that specifies the font size of the text, as a percentage.
     * If <code>labelRenderer</code> is set, this property is not used. 
     *  
     *  @default 10
     *  @ilog.reviewed SH 27 July 08
     */
    public function get percentLabelFontSize():Number
    {
      return _percentLabelFontSize;
    }

    /**
     *  @private 
     */
    public function set percentLabelFontSize(value:Number):void
    {
      _percentLabelFontSize = value;
      if (! isNaN(value))
        _labelFontSize = NaN;
      invalidateDisplayList();
    }

    /**
     *  @private 
     */
    private var _labelFontSize:Number = NaN;

    [Bindable("labelFontSizeChanged")]
    [Inspectable(category="Style")]
    [PercentProxy("percentLabelFontSize")]

    /**
     * Number that specifies the font size of the text in pixels. 
     * If <code>labelRenderer</code> is set, this property is not used. 
     *
     * <p><strong>Note:</strong> You can specify a percentage value in the MXML
     * <code>labelFontSize</code> attribute, such as <code>labelFontSize="5%"</code>,
     * but you cannot use a percentage value in the <code>labelFontSize</code>
     * property in ActionScript.
     * Use the <code>percentLabelFontSize</code> property instead.</p>
     * 
     * @default NaN
     * @ilog.reviewed SH 27 July 08 
     */
    public function get labelFontSize():Number
    {
      return _labelFontSize;
    }

    /**
     *  @private 
     */
    public function set labelFontSize(value:Number):void
    {
      _labelFontSize = value;
      if (! isNaN(value))
        _percentLabelFontSize = NaN;      
      invalidateDisplayList();      
    }

    /**
     *  @private 
     */
    private function getLabelFontSize():Number
    {
      var pr:Number = isNaN(percentLabelFontSize) ? 100 : percentLabelFontSize;      
      var rad:Number = isNaN(labelFontSize) ? getRadius() * pr/100 : labelFontSize;
      return rad;
    }
  
    [Inspectable(category="General")]
  
    /**
     * The plain text displayed by this control. 
     */    
    public function get text():String
    {
      return _text;
    }

    /**
     *  @private 
     */    
    public function set text(value:String):void
    {
      _text = value;
      invalidateProperties();
    }

    /**
     *  @private 
     */    
    override protected function commitProperties():void
    {
      if (_labelRenderer != _label)
      {
        var idr:IDataRenderer = IDataRenderer(_labelRenderer);
        idr.data = text;
      }
      else
      {  
        if (_label.text != _text)
          _label.text = _text;
      }
      invalidateSize();
      invalidateDisplayList();
    }

    /**
     * Draws the label.
     * 
     * @param unscaledWidth Specifies the width, in pixels, of the component
     * in the component's coordinates, regardless of the value of the
     * <code>scaleX</code> property of the component.
     *
     * @param unscaledHeight Specifies the height, in pixels, of the component
     * in the component's coordinates, regardless of the value of the
     * <code>scaleY</code> property of the component. 
     */    
    override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
    {
      var xOffset:Number = 0;
      var yOffset:Number = 0;
      var o:Point = getOrigin();
      if (_labelRenderer == _label)
      {
        var format:TextFormat = _label.getTextStyles();
        format.size = getLabelFontSize();
        var tmp:String = _label.text;
        _label.text = "";
        _label.text = tmp;
        _label.setTextFormat(format);
        _label.setActualSize(_label.measuredWidth, _label.measuredHeight);
      }
      var tw:Number;
      var th:Number;
      if (_labelRenderer is IFlexDisplayObject)
      {
        tw = IFlexDisplayObject(_labelRenderer).measuredWidth;
        th = IFlexDisplayObject(_labelRenderer).measuredHeight;
      }
      else
      {
        tw = _labelRenderer.width;
        th = _labelRenderer.height;
      }
      IFlexDisplayObject(_labelRenderer).setActualSize(tw, th);
      var hAlign:String = getStyle("horizontalAlign");
      var vAlign:String = getStyle("verticalAlign");      
      if (hAlign == "center")
        xOffset = - tw / 2;
      if (hAlign == "right")
        xOffset = - tw;
      if (vAlign == "middle")
        yOffset = - th / 2;
      if (vAlign == "bottom")
        yOffset = - th;
      
      if (_labelRenderer == _label)
        _label.move(o.x + xOffset, o.y + yOffset);
      else
        IFlexDisplayObject(_labelRenderer).move(o.x + xOffset, o.y + yOffset);
    }
    
    /**
     * @private
     */
    override protected function measure():void
    {
      super.measure();
      if (_labelRenderer != _label)
      {
        var ifd:IFlexDisplayObject = IFlexDisplayObject(_labelRenderer);
        measuredMinWidth = measuredWidth = ifd.measuredWidth;
        measuredMinHeight = measuredHeight= ifd.measuredHeight;
      }
      if (measuredWidth == 0 ||
          isNaN(labelFontSize))
      {
        measuredMinWidth = measuredMinHeight = measuredWidth = measuredHeight = 0;        
      }
      else
      {
        var measuringLabel:UITextField = new UITextField();
        var format:TextFormat = measuringLabel.getTextStyles();
        format.size = labelFontSize;
        measuringLabel.text = _text;
        measuringLabel.setTextFormat(format);
        measuringLabel.setActualSize(measuringLabel.measuredWidth, measuringLabel.measuredHeight);
      
        var tw:Number = measuringLabel.measuredWidth;
        var th:Number = measuringLabel.measuredHeight;
        var xOffset:Number;
        var yOffset:Number;
        
        var hAlign:String = getStyle("horizontalAlign");
        var vAlign:String = getStyle("verticalAlign");      
        if (hAlign == "center")
          xOffset = - tw / 2;
        if (hAlign == "right")
          xOffset = - tw;
        if (vAlign == "middle")
          yOffset = - th / 2;
        if (vAlign == "bottom")
          yOffset = - th;
        
        measuredMinWidth = measuredWidth = originX + xOffset + measuringLabel.measuredWidth + 2;
        measuredMinHeight = measuredHeight = originY + yOffset + measuringLabel.measuredHeight;        
      }
    }    
  }
}
